package com.fulihui.usercore.core.repository.impl;

import com.alibaba.fastjson.JSONObject;
import com.fulihui.usercore.biz.conv.UserConv;
import com.fulihui.usercore.common.util.DataSafe;
import com.fulihui.usercore.condition.UserCondition;
import com.fulihui.usercore.core.counter.AllUsersCounter;
import com.fulihui.usercore.core.repository.UserRepository;
import com.fulihui.usercore.dal.dataobj.LoginHelpDO;
import com.fulihui.usercore.dal.dataobj.UserDOExample;
import com.fulihui.usercore.dal.dataobj.UserDOWithBLOBs;
import com.fulihui.usercore.dal.mapper.Login4UidMapper;
import com.fulihui.usercore.dal.mapper.LoginHelpDOMapper;
import com.fulihui.usercore.dal.mapper.LoginMapper;
import com.fulihui.usercore.dal.mapper.UserDOMapper;
import com.fulihui.usercore.dto.UserDTO;
import com.fulihui.usercore.enums.BooleanValueEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;

import static com.fulihui.usercore.common.util.DataSafe.aesEncrypt;
import static org.near.toolkit.common.StringUtil.isNotBlank;

/**
 * @author Willard.Hu on 2016/5/19.
 */
@Repository
public class UserRepositoryImpl implements UserRepository {

    @Autowired
    private UserDOMapper userDOMapper;
    @Autowired
    private LoginMapper loginMapper;
    @Autowired
    private Login4UidMapper login4UidMapper;
    @Autowired
    private UserConv userConv;
    @Autowired
    @Lazy
    private AllUsersCounter allUsersCounter;
    @Autowired
    private LoginHelpDOMapper loginHelpDOMapper;

    /**
     * @see UserRepository#create(UserDTO)
     */
    @Override
    public String create(UserDTO userDTO) {
        String userId = String.valueOf(UUID.randomUUID());
        userDTO.setUserId(userId);
        UserDOWithBLOBs userDO = userConv.toDO(userDTO, null);
        // XXX oldUserMapper.insert(userDO);
        userDOMapper.insertSelective(userDO);
        allUsersCounter.incr();
        return userId;
    }

    /**
     * @see UserRepository#modify(UserDTO)
     */
    @Override
    public boolean modify(UserDTO userDTO) {
        // XXX UserDOWithBLOBs oldValue = oldUserMapper.queryByPK(userDTO.getUserId());
        UserDOWithBLOBs oldValue = userDOMapper.selectByPrimaryKey(userDTO.getUserId());
        UserDOWithBLOBs userDO = userConv.toDO(userDTO, JSONObject.parseObject(oldValue.getExtInfo()));
        // XXX return oldUserMapper.update(userDO);
        return userDOMapper.updateByPrimaryKeySelective(userDO) > 0;
    }

    /**
     * @see UserRepository#updateMobileNo(String, String, BooleanValueEnum)
     */
    @Override
    public boolean updateMobileNo(String mobileNo, String userId, BooleanValueEnum verified) {
        Assert.hasLength(mobileNo);
        Assert.hasLength(userId);
        String verifiedVal = verified != null ? verified.getCode() : null;

        UserDOWithBLOBs record = new UserDOWithBLOBs();
        record.setUserId(userId);
        record.setMobileNo(aesEncrypt(mobileNo, userConv.getDataSafeAesKey()));
        record.setMobileVerified(verifiedVal);
        // XXX return oldUserMapper.update(record);
        return userDOMapper.updateByPrimaryKeySelective(record) > 0;
    }

    /**
     * @see UserRepository#updateIdcard(String, String, BooleanValueEnum)
     */
    @Override
    public boolean updateIdcard(String idcard, String userId, BooleanValueEnum verified) {
        Assert.hasLength(idcard);
        Assert.hasLength(userId);
        String verifiedVal = verified != null ? verified.getCode() : null;

        UserDOWithBLOBs record = new UserDOWithBLOBs();
        record.setUserId(userId);
        record.setIdcard(aesEncrypt(idcard, userConv.getDataSafeAesKey()));
        record.setIdcardVerified(verifiedVal);
        // XXX return oldUserMapper.update(record);
        return userDOMapper.updateByPrimaryKeySelective(record) > 0;
    }

    /**
     * @see UserRepository#updateEmail(String, String, BooleanValueEnum)
     */
    @Override
    public boolean updateEmail(String email, String userId, BooleanValueEnum verified) {
        Assert.hasLength(email);
        Assert.hasLength(userId);
        String verifiedVal = verified != null ? verified.getCode() : null;

        UserDOWithBLOBs record = new UserDOWithBLOBs();
        record.setUserId(userId);
        record.setEmail(aesEncrypt(email, userConv.getDataSafeAesKey()));
        record.setEmailVerified(verifiedVal);
        // XXX return oldUserMapper.update(record);
        return userDOMapper.updateByPrimaryKeySelective(record) > 0;
    }

    /**
     * @see UserRepository#updateState(String, String)
     */
    @Override
    public boolean updateState(String state, String userId) {
        // XXX return oldUserMapper.updateState(state, userId);
        UserDOWithBLOBs record = new UserDOWithBLOBs();
        record.setUserId(userId);
        record.setState(state);
        return userDOMapper.updateByPrimaryKeySelective(record) > 0;
    }

    /**
     * @see UserRepository#queryByPK(String)
     */
    @Override
    public UserDTO queryByPK(String userId) {
        // XXX UserDOWithBLOBs userDO = oldUserMapper.queryByPK(userId);
        UserDOWithBLOBs userDO = userDOMapper.selectByPrimaryKey(userId);
        return userConv.toDTO(userDO);
    }

    /**
     * @see UserRepository#queryByLoginId(String)
     */
    @Override
    public UserDTO queryByLoginId(String loginId) {
        //分表分库，根据loginid查询的，走辅助表
        LoginHelpDO loginHelpDO = loginHelpDOMapper.selectByPrimaryKey(loginId);
        if (loginHelpDO == null) {
            return null;
        }
//        LoginDO userLoginDO = loginMapper.queryByPK(loginId);
//        if (userLoginDO == null) {
//            return null;
//        }
        // XXX UserDOWithBLOBs userDO = oldUserMapper.queryByPK(userLoginDO.getUserId());
        UserDOWithBLOBs userDO = userDOMapper.selectByPrimaryKey(loginHelpDO.getUserId());
        return userConv.toDTO(userDO);
    }

    /**
     * @see UserRepository#queryByUserIds(List)
     */
    @Override
    public List<UserDTO> queryByUserIds(List<String> userIds) {
        if (CollectionUtils.isEmpty(userIds)) {
            return Collections.emptyList();
        }
        // XXX List<UserDOWithBLOBs> doList = oldUserMapper.queryByUserIds(userIds);
        UserDOExample example = new UserDOExample();
        example.createCriteria().andUserIdIn(userIds);
        List<UserDOWithBLOBs> doList = userDOMapper.selectByExampleWithBLOBs(example);
        return userConv.toList(doList);
    }

    /**
     * @see UserRepository#queryByUserIdsToMap(List)
     */
    @Override
    public Map<String, UserDTO> queryByUserIdsToMap(List<String> userIds) {
        if (CollectionUtils.isEmpty(userIds)) {
            return Collections.emptyMap();
        }
        // XXX List<UserDOWithBLOBs> doList = oldUserMapper.queryByUserIds(userIds);
        UserDOExample example = new UserDOExample();
        example.createCriteria().andUserIdIn(userIds);
        List<UserDOWithBLOBs> doList = userDOMapper.selectByExampleWithBLOBs(example);
        return userConv.toMap(doList);
    }

    /**
     * @see UserRepository#queryByNickname(String)
     */
    @Override
    public List<UserDTO> queryByNickname(String nickname) {
        Optional<String> optional = DataSafe.baseEncode(nickname);
        if (!optional.isPresent()) {
            return Collections.emptyList();
        }
        // XXX List<UserDOWithBLOBs> doList = oldUserMapper.queryByNickname(optional.get());
        UserDOExample example = new UserDOExample();
        example.createCriteria().andNicknameEqualTo(optional.get());
        List<UserDOWithBLOBs> doList = userDOMapper.selectByExampleWithBLOBs(example);
        return userConv.toList(doList);
    }

    /**
     * @see UserRepository#queryPage(int, int, UserCondition)
     */
    @Override
    public List<UserDTO> queryPage(int start, int rows, UserCondition condition) {
        /* XXX
        String encryptMobile = isNotBlank(condition.getMobileNo()) ?
                aesEncrypt(condition.getMobileNo(), userConv.getDataSafeAesKey()) : null;
        List<UserDOWithBLOBs> doList = oldUserMapper.queryPage(start, rows, condition.getMobileNo(),
                encryptMobile, condition.getProvince(), condition.getCity(), condition.getTagId(),
                condition.getRegisterSource(), condition.getRegisterStartDate(),
                condition.getRegisterEndDate(), condition.getState());*/

        UserDOExample example = new UserDOExample();
        UserDOExample.Criteria criteria = example.createCriteria();
        setCriteria(criteria, condition);
        // XXX tagId query
        example.setOffset(start);
        example.setLimit(rows);
        example.setOrderByClause("gmt_create desc");
        List<UserDOWithBLOBs> doList = userDOMapper.selectByExampleWithBLOBs(example);
        return userConv.toList(doList);
    }

    /**
     * @see UserRepository#totalCount(UserCondition)
     */
    @Override
    public long totalCount(UserCondition condition) {
        /* XXX
        String encryptMobile = isNotBlank(condition.getMobileNo()) ?
                aesEncrypt(condition.getMobileNo(), userConv.getDataSafeAesKey()) : null;
        return oldUserMapper.totalCount(condition.getMobileNo(), encryptMobile, condition.getProvince(),
                condition.getCity(), condition.getTagId(), condition.getRegisterSource(),
                condition.getRegisterStartDate(), condition.getRegisterEndDate(), condition.getState());*/

        UserDOExample example = new UserDOExample();
        UserDOExample.Criteria criteria = example.createCriteria();
        setCriteria(criteria, condition);
        return userDOMapper.countByExample(example);
    }

    private void setCriteria(UserDOExample.Criteria criteria, UserCondition condition) {
        String encryptMobile = isNotBlank(condition.getMobileNo()) ?
                aesEncrypt(condition.getMobileNo(), userConv.getDataSafeAesKey()) : null;

        if (isNotBlank(condition.getMobileNo())) {
            criteria.andMobileNoIn(Arrays.asList(condition.getMobileNo(), encryptMobile));
        }
        if (isNotBlank(condition.getProvince())) {
            criteria.andProvinceEqualTo(condition.getProvince());
        }
        if (isNotBlank(condition.getCity())) {
            criteria.andCityEqualTo(condition.getCity());
        }
        if (isNotBlank(condition.getRegisterSource())) {
            criteria.andRegisterSourceEqualTo(condition.getRegisterSource());
        }
        if (condition.getRegisterStartDate() != null) {
            criteria.andGmtCreateGreaterThanOrEqualTo(condition.getRegisterStartDate());
        }
        if (condition.getRegisterEndDate() != null) {
            criteria.andGmtCreateLessThan(condition.getRegisterEndDate());
        }
        if (isNotBlank(condition.getState())) {
            criteria.andStateEqualTo(condition.getState());
        }
    }

}
